package system

import (
	"context"
	"errors"
	"fmt"
	"github.com/flipped-aurora/gin-vue-admin/server/global"
	"github.com/flipped-aurora/gin-vue-admin/server/model/system"
	systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
	"go.uber.org/zap"
	"strings"
	"time"
)

type SeckillOrderService struct{}

// CreateSeckillOrder 创建秒杀订单表记录
// Author [yourname](https://github.com/yourname)
func (seckillOrderService *SeckillOrderService) CreateSeckillOrder(ctx context.Context, seckillOrder *system.SeckillOrder) (err error) {
	err = global.GVA_DB.Create(seckillOrder).Error
	return err
}

// DeleteSeckillOrder 删除秒杀订单表记录
// Author [yourname](https://github.com/yourname)
func (seckillOrderService *SeckillOrderService) DeleteSeckillOrder(ctx context.Context, ID string) (err error) {
	err = global.GVA_DB.Delete(&system.SeckillOrder{}, "id = ?", ID).Error
	return err
}

// DeleteSeckillOrderByIds 批量删除秒杀订单表记录
// Author [yourname](https://github.com/yourname)
func (seckillOrderService *SeckillOrderService) DeleteSeckillOrderByIds(ctx context.Context, IDs []string) (err error) {
	err = global.GVA_DB.Delete(&[]system.SeckillOrder{}, "id in ?", IDs).Error
	return err
}

// UpdateSeckillOrder 更新秒杀订单表记录
// Author [yourname](https://github.com/yourname)
func (seckillOrderService *SeckillOrderService) UpdateSeckillOrder(ctx context.Context, seckillOrder system.SeckillOrder) (err error) {
	err = global.GVA_DB.Model(&system.SeckillOrder{}).Where("id = ?", seckillOrder.ID).Updates(&seckillOrder).Error
	return err
}

// GetSeckillOrder 根据ID获取秒杀订单表记录
// Author [yourname](https://github.com/yourname)
func (seckillOrderService *SeckillOrderService) GetSeckillOrder(ctx context.Context, ID string) (seckillOrder system.SeckillOrder, err error) {
	err = global.GVA_DB.Where("id = ?", ID).First(&seckillOrder).Error
	return
}

// GetSeckillOrderInfoList 分页获取秒杀订单表记录
// Author [yourname](https://github.com/yourname)
func (seckillOrderService *SeckillOrderService) GetSeckillOrderInfoList(ctx context.Context, info systemReq.SeckillOrderSearch) (list []system.SeckillOrder, total int64, err error) {
	limit := info.PageSize
	offset := info.PageSize * (info.Page - 1)
	// 创建db
	db := global.GVA_DB.Model(&system.SeckillOrder{})
	var seckillOrders []system.SeckillOrder
	// 如果有条件搜索 下方会自动创建搜索语句
	if len(info.CreatedAtRange) == 2 {
		db = db.Where("created_at BETWEEN ? AND ?", info.CreatedAtRange[0], info.CreatedAtRange[1])
	}

	err = db.Count(&total).Error
	if err != nil {
		return
	}

	if limit != 0 {
		db = db.Limit(limit).Offset(offset)
	}

	err = db.Find(&seckillOrders).Error
	return seckillOrders, total, err
}
func (seckillOrderService *SeckillOrderService) GetSeckillOrderPublic(ctx context.Context) {
	// 此方法为获取数据源定义的数据
	// 请自行实现
}

// SeckillOrderPay 订单支付
// Author [yourname](https://github.com/yourname)
func (seckillOrderService *SeckillOrderService) SeckillOrderPay(orderSn string) (string, error) {
	var order system.SeckillOrder
	if err := global.GVA_DB.Where("order_sn = ?", orderSn).First(&order).Error; err != nil {
		return "", errors.New("订单不存在")
	}
	// 只允许待支付订单
	status := ""
	if order.Seckill_order_status != nil {
		status = strings.TrimSpace(fmt.Sprintf("%v", *order.Seckill_order_status))
	}
	if status != "待支付" && status != "1" {
		return "", errors.New("订单状态不允许支付")
	}
	ali := AliPay{
		Subject:     "秒杀订单",
		OutTradeNo:  orderSn,
		TotalAmount: *order.Amount,
	}
	return ali.Pay(), nil
}

// HandlePaymentSuccess 处理支付成功
// Author [yourname](https://github.com/yourname)
func (seckillOrderService *SeckillOrderService) HandlePaymentSuccess(orderSn string) error {
	// 1. 查询订单信息
	var order system.SeckillOrder
	if err := global.GVA_DB.Where("order_sn = ?", orderSn).First(&order).Error; err != nil {
		return fmt.Errorf("订单不存在: %w", err)
	}

	// 2. 检查订单状态，避免重复处理
	status := ""
	if order.Seckill_order_status != nil {
		status = strings.TrimSpace(fmt.Sprintf("%v", *order.Seckill_order_status))
	}
	if status == "已支付" || status == "2" {
		return nil // 已经处理过了
	}

	// 3. 开始事务
	tx := global.GVA_DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 4. 更新订单状态为已支付
	err := tx.Model(&system.SeckillOrder{}).Where("order_sn = ?", orderSn).Update("seckill_order_status", "已支付").Error
	if err != nil {
		tx.Rollback()
		return fmt.Errorf("更新订单状态失败: %w", err)
	}

	// 5. 提交事务
	err = tx.Commit().Error
	if err != nil {
		return fmt.Errorf("提交事务失败: %w", err)
	}

	return nil
}

// RollbackUnusedStock 活动结束后回滚未用完的库存
// Author [yourname](https://github.com/yourname)
func (seckillOrderService *SeckillOrderService) RollbackUnusedStock(activityId uint) error {
	// 1. 查询活动信息
	var activity system.Seckill_activity
	if err := global.GVA_DB.Where("id = ?", activityId).First(&activity).Error; err != nil {
		return fmt.Errorf("活动不存在: %w", err)
	}

	// 2. 检查活动是否已结束
	if activity.Seckill_end_time != nil {
		var endTime time.Time
		var err error

		endTime, err = time.Parse("2006-01-02", *activity.Seckill_end_time)
		if err != nil {
			return fmt.Errorf("活动结束时间格式错误: %w", err)
		}

		if endTime.After(time.Now()) {
			return fmt.Errorf("活动尚未结束，无法回滚库存")
		}
	}

	// 3. 查询该活动下的所有设备
	var activityDevices []system.Seckill_activity_device
	if err := global.GVA_DB.Where("seckill_activity_id = ?", activityId).Find(&activityDevices).Error; err != nil {
		return fmt.Errorf("查询活动设备失败: %w", err)
	}

	// 4. 开始事务
	tx := global.GVA_DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	ctx := context.Background()
	totalRollbackCount := 0

	// 5. 遍历每个设备，回滚未用完的库存
	for _, device := range activityDevices {
		redisKey := fmt.Sprintf("seckill:stock:%d", device.ID)

		// 获取Redis中剩余的库存数量
		remainingStock, err := global.GVA_REDIS.LLen(ctx, redisKey).Result()
		if err != nil {
			global.GVA_LOG.Warn("获取Redis库存失败", zap.Error(err), zap.Uint("device_id", device.ID))
			continue
		}

		if remainingStock > 0 {
			// 回滚到医疗设备表
			err = tx.Model(&system.Decimal_device{}).
				Where("id = ?", device.Seckill_decimal_device_id).
				Update("stock", global.GVA_DB.Raw("stock + ?", remainingStock)).Error
			if err != nil {
				tx.Rollback()
				return fmt.Errorf("回滚医疗设备库存失败: %w", err)
			}

			// 清空Redis库存
			err = global.GVA_REDIS.Del(ctx, redisKey).Err()
			if err != nil {
				global.GVA_LOG.Warn("清空Redis库存失败", zap.Error(err), zap.Uint("device_id", device.ID))
			}

			// 更新活动设备库存为0
			err = tx.Model(&system.Seckill_activity_device{}).
				Where("id = ?", device.ID).
				Update("stock", 0).Error
			if err != nil {
				tx.Rollback()
				return fmt.Errorf("更新活动设备库存失败: %w", err)
			}

			totalRollbackCount += int(remainingStock)

			global.GVA_LOG.Info("设备库存回滚成功",
				zap.Uint("device_id", device.ID),
				zap.Int64("rollback_stock", remainingStock))
		}
	}

	// 6. 提交事务
	err := tx.Commit().Error
	if err != nil {
		return fmt.Errorf("提交事务失败: %w", err)
	}

	global.GVA_LOG.Info("活动库存回滚完成",
		zap.Uint("activity_id", activityId),
		zap.Int("total_rollback_count", totalRollbackCount))

	return nil
}
